#!/usr/bin/env python
# API calls
#
# http://api.jamendo.com/get2/stream/track/m3u/?id=116&streamencoding=ogg2
# http://api.jamendo.com/get2/stream/track/m3u/?album_id=116&streamencoding=ogg2
# http://api.jamendo.com/get2/stream/album/m3u/?artist_id=5&streamencoding=ogg2

import logging
import Queue
import os.path
import sha
import sys
import threading
import time
import urllib

log = logging.getLogger('download_queue').info

URLS = {
    'track': 'http://api.jamendo.com/get2/stream/track/m3u/?id=%s&streamencoding=ogg2&n=all',
    'album': 'http://api.jamendo.com/get2/stream/track/m3u/?album_id=%s&streamencoding=ogg2&n=all',
    'artist': 'http://api.jamendo.com/get2/stream/album/m3u/?artist_id=%s&streamencoding=ogg2&n=all',
    }

ARTIST_LOOKUP_URL = 'http://api.jamendo.com/get2/id/artist/plain/?idstr=%s'

class Downloader(object):
    def __init__(self, out_dir):
        self.queue = Queue.Queue()
        self.out_dir = out_dir
        self.sleep_time = 0

    def add(self, url):
        if not url.startswith('http://'):
            log('Not adding invalid URL %s' % url)
        else:
            log('Adding to queue ' + url)
            self.queue.put(url)

    def add_smart(self, type, identifier):
        identifier = urllib.quote_plus(urllib.unquote_plus(identifier))
        if type == 'artistname':
            try:
                id = int(self.get_contents(ARTIST_LOOKUP_URL % identifier))
            except ValueError:
                log('Unknown artist %s' % identifier)
                return False
            else:
                if id == 0:
                    log('Uknown artist %s' % identifier)
                    return False
            type = 'artist'
            identifier = str(id)
        if type not in URLS:
            log('Ignoring smart add for unknown type %s' % type)
            return False
        else:
            self.add(URLS[type] % identifier)
            return True

    def run(self):
        while not self.should_stop():
            log('%d URLs to fetch' % self.queue.qsize())
            time.sleep(self.sleep_time)
            url = self.queue.get()
            if url.endswith('.ogg'):
                self.download_ogg(url)
            elif url.endswith('.mp3'):
                raise AssertionError('No mp3 should be downloaded')
            else:
                self.download_m3u(url)

    def should_stop(self):
        return self.queue.empty()

    def get_contents(self, url):
        fd = urllib.urlopen(url)
        data = fd.read()
        fd.close()
        return data

    def download_ogg(self, url):
        log('Downloading OGG ' + url)
        data = self.get_contents(url)

        filename = os.path.join(self.out_dir,
                                sha.new(data).hexdigest() + '.ogg')
        fd = open(filename, 'w')
        fd.write(data)
        fd.close()
        log('Saved as ' + filename)
        self.sleep_time = 5

    def download_m3u(self, url):
        # Some parameters gets stripped sometimes, check and possibly
        # add back
        if '&streamencoding' not in url:
            url += '&streamencoding=ogg2'
        if '&n=' not in url:
            url += '&n=all'

        log('Downloading M3U ' + url)
        data = self.get_contents(url)
        for line in data.split('\n'):
            if not line.strip() or line.strip().startswith('#'):
                continue
            self.add(line)
        self.sleep_time = 1

def main():
    logging.basicConfig(level=logging.INFO)
    if len(sys.argv) != 4:
        print 'Usage: %s <output dir> (artist|album|track) <entity ID>' % sys.argv[0]
        sys.exit(2)
    out_dir, type, identifier = sys.argv[1:4]
    if not os.path.isdir(out_dir):
        print 'Output directory %s does not exist' % out_dir
        sys.exit(2)
    if type not in URLS:
        print 'Unknown entity type %s' % type
        sys.exit(2)

    d = Downloader(out_dir)
    d.add_smart(type, identifier)
    d.run()

    print 'Retrieval complete.'

if __name__ == '__main__':
    main()
